package main.java.indi.zyj.hot100;

import java.util.*;

public class _72_canFinish {

    public boolean canFinish(int numCourses, int[][] prerequisites) {

        Map<Integer, ArrayList<Integer>> map = new HashMap<>();
        int[] inDegree = new int[numCourses];

        // prerequisite (0, 1)    0 <- 1
        for (int[] prerequisite : prerequisites) {
            ArrayList<Integer> node = map.getOrDefault(prerequisite[0], new ArrayList<>());
            node.add(prerequisite[1]);
            inDegree[prerequisite[0]]++;
        }

        LinkedList<Integer> queue = new LinkedList<>();
        for (int i = 0; i < numCourses; i++) {
            if (inDegree[i] == 0) {
                queue.offer(i);
            }
        }

        int count = 0;
        while (!queue.isEmpty()) {
            Integer curNode = queue.poll();
            ArrayList<Integer> nodeList = map.get(curNode);
            for (Integer node : nodeList) {
                if (--inDegree[node] == 0) {
                    queue.offer(node);
                }
            }
            count++;
        }

        return count == numCourses;
    }



    public boolean canFinishList(int numCourses, int[][] prerequisites) {
        //初始化邻接表
        ArrayList<ArrayList<Integer>> graph = new ArrayList<>();

        for (int i = 0; i < numCourses; i++) {
            graph.add(new ArrayList<>());
        }

        //准备入度表
        int [] inDegree = new int[numCourses];

        for (int[] p : prerequisites) {
            // (1, 2) 1<-2 ARRAY(2){1}  indegree(1)++
            graph.get(p[1]).add(p[0]); // 指向的队列
            inDegree[p[0]]++;          // 入度++
        }

        //寻找入度为0的点，消除它对其他点的影响
        //使用队列存储入度为0的点
        LinkedList<Integer> queue = new LinkedList<>();
        for (int i = 0; i < inDegree.length; i++) {
            if (inDegree[i]==0){
                queue.offer(i);
            }
        }

        //统计队列弹出的点
        int count = 0;
        //不断寻找入度为0的点
        while (!queue.isEmpty()){
            //在邻接表中寻找当前点的所有邻接点
            Integer poll = queue.poll();
            count++;
            ArrayList<Integer> list = graph.get(poll);

            //遍历集合消除当前点对其他点的影响，也就是其他点的入度-1
            for (Integer integer : list) {
                //一旦入度减完之后发现有节点入度为0的直接入队
                if (--inDegree[integer] == 0) {
                    queue.offer(integer);
                }
            }
        }

        //判断是否存在环也就是是否能学习完所有课程的关键
        return count == numCourses;
    }
}
